/**
 * 主要的逻辑在 main.js 实现, 然后供 www.js 引用
 */
const http = require('http')
const url = require('url')
const path = require('path')
const mime = require('mime')
const ejs = require('ejs')
const fs = require('fs').promises
const { createReadStream } = require('fs')
const { promisify } = require('util')

function mergeConfig(config) {
  return {
    port: 1234,
    directory: process.cwd(),
    ...config,
  }
}

class Server {
  constructor(config) {
    this.config = mergeConfig(config)
  }
  start() {
    // this 当前实例对象
    let server = http.createServer(this.serverHandle.bind(this))
    server.listen(this.config.port, () => {
      console.info(`服务端已经启动了 http://localhost:${this.config.port}`)
    })
  }

  async serverHandle(req, res) {
    let { pathname } = url.parse(req.url)
    pathname = decodeURIComponent(pathname)

    let absPath = path.join(this.config.directory, pathname)

    try {
      let statObj = await fs.stat(absPath)

      // 处理文件
      if (statObj.isFile()) {
        this.fileHandle(req, res, absPath)
      } else {
        // 处理目录

        // 读取目录
        let dirs = await fs.readdir(absPath)
        dirs = dirs.map((item) => {
          return {
            path: path.join(pathname, item),
            dirs: item,
          }
        })
        // promisify 方法
        let renderFile = promisify(ejs.renderFile)

        let parentPath = path.dirname(pathname)
        // 传递数据渲染模板
        let ret = await renderFile(path.resolve(__dirname, 'template.html'), {
          arr: dirs,
          parent: pathname !== '/',
          parentPath: parentPath,
          title: path.basename(absPath),
        })
        res.end(ret)
      }
    } catch (error) {
      this.errorHandle(req, res, error)
    }
  }

  errorHandle(req, res, err) {
    console.info(err)
    res.statusCode = 404
    res.setHeader('Content-type', `text/html;charset=utf-8`)
    res.end('Page Not Found!')
  }

  fileHandle(req, res, absPath) {
    res.statusCode = 200
    res.setHeader('Content-type', `${mime.getType(absPath)};charset=utf-8`)
    createReadStream(absPath).pipe(res)
  }
}

module.exports = Server
